//===--- StdlibUnittest.swift.gyb -----------------------------*- swift -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import SwiftPrivate
import SwiftPrivatePthreadExtras
import SwiftPrivateLibcExtras

#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin
#elseif os(Linux) || os(FreeBSD)
import Glibc
#endif

#if _runtime(_ObjC)
import ObjectiveC
#endif

public struct SourceLoc {
  public let file: String
  public let line: UInt
  public let comment: String?

  public init(_ file: String, _ line: UInt, comment: String? = nil) {
    self.file = file
    self.line = line
    self.comment = comment
  }

  public func withCurrentLoc(
      _ file: String = #file, line: UInt = #line
  ) -> SourceLocStack {
    return SourceLocStack(self).with(SourceLoc(file, line))
  }
}

public struct SourceLocStack {
  let locs: [SourceLoc]

  public init() {
    locs = []
  }

  public init(_ loc: SourceLoc) {
    locs = [ loc ]
  }

  init(_locs: [SourceLoc]) {
    locs = _locs
  }

  var isEmpty: Bool {
    return locs.isEmpty
  }

  public func with(_ loc: SourceLoc) -> SourceLocStack {
    var locs = self.locs
    locs.append(loc)
    return SourceLocStack(_locs: locs)
  }

  public func pushIf(
    _ showFrame: Bool, file: String, line: UInt
  ) -> SourceLocStack {
    return showFrame ? self.with(SourceLoc(file, line)) : self
  }

  public func withCurrentLoc(
      _ file: String = #file, line: UInt = #line
  ) -> SourceLocStack {
    return with(SourceLoc(file, line))
  }

  public func print() {
    let top = locs.first!
    Swift.print("check failed at \(top.file), line \(top.line)")
    _printStackTrace(SourceLocStack(_locs: Array(locs.dropFirst())))
  }
}

%{
  TRACE = '''@autoclosure _ message: () -> String = "",
    showFrame: Bool = true,
    stackTrace: SourceLocStack = SourceLocStack(),  
    file: String = #file, line: UInt = #line'''
  
  stackTrace = 'stackTrace.pushIf(showFrame, file: file, line: line)'

  trace = 'message(),\n  stackTrace: ' + stackTrace
}%

func _printStackTrace(_ stackTrace: SourceLocStack?) {
  guard let s = stackTrace where !s.locs.isEmpty else { return }
  print("stacktrace:")
  for (i, loc) in s.locs.reversed().enumerated() {
    let comment = (loc.comment != nil) ? " ; \(loc.comment!)" : ""
    print("  #\(i): \(loc.file):\(loc.line)\(comment)")
  }
}

// FIXME: these variables should be atomic, since multiple threads can call
// `expect*()` functions.
var _anyExpectFailed = false
var _seenExpectCrash = false

/// Run `body` and expect a failure to happen.
///
/// The check passes iff `body` triggers one or more failures.
public func expectFailure(${TRACE}, body: () -> Void) {
  let startAnyExpectFailed = _anyExpectFailed
  _anyExpectFailed = false
  body()
  let endAnyExpectFailed = _anyExpectFailed
  _anyExpectFailed = false
  expectTrue(
    endAnyExpectFailed, "running `body` should produce an expected failure",
    stackTrace: ${stackTrace}
  )
  _anyExpectFailed = _anyExpectFailed || startAnyExpectFailed
}

public func identity(_ element: OpaqueValue<Int>) -> OpaqueValue<Int> {
  return element
}

public func identityEq(_ element: MinimalEquatableValue) -> MinimalEquatableValue {
  return element
}

public func identityComp(_ element: MinimalComparableValue)
  -> MinimalComparableValue {
  return element
}

public func expectEqual<T : Equatable>(_ expected: T, _ actual: T, ${TRACE}) {
  expectEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}

public func expectEqual<T : Equatable, U : Equatable>(
  _ expected: (T, U), _ actual: (T, U), ${TRACE}) {
  expectEqual(expected.0, actual.0, ${trace}, showFrame: false) {$0 == $1}
  expectEqual(expected.1, actual.1, ${trace}, showFrame: false) {$0 == $1}
}

public func expectationFailure(
  _ reason: String,
  trace message: String,
  stackTrace: SourceLocStack) {
  _anyExpectFailed = true
  stackTrace.print()
  print(reason, terminator: reason == "" ? "" : "\n")
  print(message, terminator: message == "" ? "" : "\n")
}

public func expectEqual<T>(
  _ expected: T, _ actual: T, ${TRACE}, sameValue equal: (T,T) -> Bool
) {
  if !equal(expected, actual) {
    expectationFailure(
      "expected: \(String(reflecting: expected)) (of type \(String(reflecting: expected.dynamicType)))\n"
      + "actual: \(String(reflecting: actual)) (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace}
    )
  }
}

public func expectNotEqual<T : Equatable>(_ expected: T, _ actual: T, ${TRACE}) {
  if expected == actual {
    expectationFailure(
      "unexpected value: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace}
    )
  }
}

// Cannot write a sane set of overloads using generics because of:
// <rdar://problem/17015923> Array->NSArray implicit conversion insanity
public func expectOptionalEqual<T : Equatable>(
  _ expected: T, _ actual: T?, ${TRACE}
) {
  expectOptionalEqual(expected, actual, ${trace}, showFrame: false) {$0 == $1}
}

public func expectOptionalEqual<T>(
  _ expected: T, _ actual: T?, ${TRACE}, sameValue equal: (T,T) -> Bool
) {
  if (actual == nil) || !equal(expected, actual!) {
    expectationFailure(
      "expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
      + "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace})
  }
}

public func expectEqual<T : Equatable>(_ expected: T?, _ actual: T?, ${TRACE}) {
  if (actual == nil) != (expected == nil)
    || actual != nil && expected! != actual! {
    expectationFailure(
      "expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))\n"
      + "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace})
  }
}

// Array<T> is not Equatable if T is.  Provide additional overloads.
// Same for Dictionary.
%for (Generic, EquatableType) in [
%    ('<T : Equatable>', 'ContiguousArray<T>'),
%    ('<T : Equatable>', 'ArraySlice<T>'),
%    ('<T : Equatable>', 'Array<T>'),
%    ('<T, U : Equatable>', 'Dictionary<T, U>')]:

public func expectEqual${Generic}(
  _ expected: ${EquatableType}, _ actual: ${EquatableType}, ${TRACE}
) {
  expectEqual(expected, actual, ${trace}, showFrame: false) { $0 == $1 }
}

public func expectOptionalEqual${Generic}(
    _ expected: ${EquatableType}, _ actual: ${EquatableType}?, ${TRACE}) {
  if (actual == nil) || expected != actual! {
    expectationFailure(
      "expected: \"\(expected)\" (of type \(String(reflecting: expected.dynamicType)))"
      + "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace})
  }
}

%end

public func expectLT(_ lhs: Int, _ rhs: Int, ${TRACE}) {
  if !(lhs < rhs) {
    expectationFailure("\(lhs) < \(rhs)", trace: ${trace})
  }
}

public func expectLE(_ lhs: Int, _ rhs: Int, ${TRACE}) {
  if !(lhs <= rhs) {
    expectationFailure("\(lhs) <= \(rhs)", trace: ${trace})
  }
}

public func expectGT(_ lhs: Int, _ rhs: Int, ${TRACE}) {
  if !(lhs > rhs) {
    expectationFailure("\(lhs) > \(rhs)", trace: ${trace})
  }
}

public func expectGE(_ lhs: Int, _ rhs: Int, ${TRACE}) {
  if !(lhs >= rhs) {
    expectationFailure("\(lhs) >= \(rhs)", trace: ${trace})
  }
}

public func expectType<T>(_: T.Type, _ x: inout T) {}
public func expectEqualType<T>(_: T.Type, _: T.Type) {}

public func expectSequenceType<
  X : Sequence
  where
  X.SubSequence : Sequence,
  X.SubSequence.Iterator.Element == X.Iterator.Element,
  X.SubSequence.SubSequence == X.SubSequence
>(_ x: X) -> X { return x }

public func expectIndexable<X : Indexable>(_ x: X) -> X { return x }
public func expectCollectionType<
  X : Collection
  where
  X.SubSequence : Collection,
  X.SubSequence.Iterator.Element == X.Iterator.Element,
  X.SubSequence.SubSequence == X.SubSequence
>(_ x: X) -> X { return x }

/// A slice is a `Collection` that when sliced returns an instance of
/// itself.
public func expectSliceType<
  X : Collection
  where
  X.SubSequence == X
>(_ sliceType: X.Type) {}

/// A mutable slice is a `MutableCollection` that when sliced returns an
/// instance of itself.
public func expectMutableSliceType<
  X : MutableCollection
  where
  X.SubSequence == X
>(_ mutableSliceType: X.Type) {}

/// Check all associated types of a `Collection`.
public func expectCollectionAssociatedTypes<
  X : Collection,
  Iterator : IteratorProtocol,
  SubSequence : Sequence,
  Index : ForwardIndex
  where
  X.Index == Index
>(
  collectionType: X.Type,
  iteratorType: Iterator.Type,
  subSequenceType: SubSequence.Type,
  indexType: Index.Type
) {}

public func expectForwardIndexType<X : ForwardIndex>(_ x: X) -> X { return x }
public func expectIsBooleanType<X : Boolean>(_ x: inout X) -> X { return x }

public struct AssertionResult : CustomStringConvertible, Boolean {
  init(isPass: Bool) {
    self._isPass = isPass
  }

  public var boolValue: Bool {
    return _isPass
  }

  public func withDescription(_ description: String) -> AssertionResult {
    var result = self
    result.description += description
    return result
  }

  let _isPass: Bool

  public var description: String = ""
}

public func assertionSuccess() -> AssertionResult {
  return AssertionResult(isPass: true)
}

public func assertionFailure() -> AssertionResult {
  return AssertionResult(isPass: false)
}

public func expectUnreachable(${TRACE}) {
  expectationFailure("this code should not be executed", trace: ${trace})
}

public func expectUnreachableCatch(_ error: ErrorProtocol, ${TRACE}) {
  expectationFailure(
    "error should not be thrown: \"\(error)\"", trace: ${trace})
}

%for BoolType in ['Bool', 'AssertionResult']:

public func expectTrue(_ actual: ${BoolType}, ${TRACE}) {
  if !actual {
    expectationFailure("expected: true", trace: ${trace})
  }
}

public func expectFalse(_ actual: ${BoolType}, ${TRACE}) {
  if actual {
    expectationFailure("expected: false", trace: ${trace})
  }
}

%end

public func expectEmpty<T>(_ value: T?, ${TRACE}) {
  if value != nil {
    expectationFailure(
      "expected optional to be empty\nactual: \"\(value)\"", trace: ${trace})
  }
}

public func expectNotEmpty<T>(_ value: T?, ${TRACE}) -> T? {
  if value == nil {
    expectationFailure("expected optional to be non-empty", trace: ${trace})
  }
  return value
}

public func expectCrashLater() {
  print("\(_stdlibUnittestStreamPrefix);expectCrash;\(_anyExpectFailed)")

  var stderr = _Stderr()
  print("\(_stdlibUnittestStreamPrefix);expectCrash", to: &stderr)

  _seenExpectCrash = true
}

func _defaultTestSuiteFailedCallback() {
  abort()
}

var _testSuiteFailedCallback: () -> Void = _defaultTestSuiteFailedCallback

public func _setTestSuiteFailedCallback(_ callback: () -> Void) {
  _testSuiteFailedCallback = callback
}

extension ProcessTerminationStatus {
  var isSwiftTrap: Bool {
    switch self {
    case .exit(_):
      return false
    case .signal(let signal):
      return CInt(signal) == SIGILL || CInt(signal) == SIGTRAP
    default:
      fatalError("Bad ProcessTerminationStatus")
    }
  }
}

func _stdlib_getline() -> String? {
  var result: [UInt8] = []
  while true {
    let c = getchar()
    if c == EOF {
      if result.isEmpty {
        return nil
      }
      return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
    }
    if c == CInt(UnicodeScalar("\n").value) {
      return String._fromWellFormedCodeUnitSequence(UTF8.self, input: result)
    }
    result.append(UInt8(c))
  }
}

func _printDebuggingAdvice(_ fullTestName: String) {
  print("To debug, run:")
  print("$ \(Process.arguments[0]) " +
    "--stdlib-unittest-in-process --stdlib-unittest-filter \"\(fullTestName)\"")
}

var _allTestSuites: [TestSuite] = []
var _testSuiteNameToIndex: [String : Int] = [:]

let _stdlibUnittestStreamPrefix = "__STDLIB_UNITTEST__"
let _crashedPrefix = "CRASHED:"

@_silgen_name("swift_stdlib_installTrapInterceptor")
func _stdlib_installTrapInterceptor()

#if _runtime(_ObjC)
@objc protocol _StdlibUnittestNSException {
  optional var name: AnyObject { get }
}
#endif

func _childProcess() {
  _stdlib_installTrapInterceptor()

#if _runtime(_ObjC)
  objc_setUncaughtExceptionHandler {
    var stderr = _Stderr()
    let maybeNSException = unsafeBitCast($0, to:_StdlibUnittestNSException.self)
    if let name = maybeNSException.name {
      print("*** [StdlibUnittest] Terminating due to uncaught exception " +
        "\(name): \($0)",
        to: &stderr)
    } else {
      print("*** [StdlibUnittest] Terminating due to uncaught exception: \($0)",
        to: &stderr)      
    }
  }
#endif

  while let line = _stdlib_getline() {
    let parts = line._split(separator: ";")
    let testSuiteName = parts[0]
    let testName = parts[1]
    var testParameter: Int?
    if parts.count > 2 {
      testParameter = Int(parts[2])!
    } else {
      testParameter = nil
    }

    let testSuite = _allTestSuites[_testSuiteNameToIndex[testSuiteName]!]
    _anyExpectFailed = false
    testSuite._runTest(name: testName, parameter: testParameter)

    print("\(_stdlibUnittestStreamPrefix);end;\(_anyExpectFailed)")

    var stderr = _Stderr()
    print("\(_stdlibUnittestStreamPrefix);end", to: &stderr)

    if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
      return
    }
  }
}

struct _ParentProcess {
  internal var _pid: pid_t = -1
  internal var _childStdin: _FDOutputStream = _FDOutputStream(fd: -1)
  internal var _childStdout: _FDInputStream = _FDInputStream(fd: -1)
  internal var _childStderr: _FDInputStream = _FDInputStream(fd: -1)

  internal var _runTestsInProcess: Bool
  internal var _filter: String?
  internal var _args: [String]

  init(runTestsInProcess: Bool, args: [String], filter: String?) {
    self._runTestsInProcess = runTestsInProcess
    self._filter = filter
    self._args = args
  }

  mutating func _spawnChild() {
    let params = [ "--stdlib-unittest-run-child" ] + _args
    let (pid, childStdinFD, childStdoutFD, childStderrFD) = spawnChild(params)
    _pid = pid
    _childStdin = _FDOutputStream(fd: childStdinFD)
    _childStdout = _FDInputStream(fd: childStdoutFD)
    _childStderr = _FDInputStream(fd: childStderrFD)
  }

  mutating func _waitForChild() -> ProcessTerminationStatus {
    let status = posixWaitpid(_pid)
    _pid = -1
    _childStdin.close()
    _childStdout.close()
    _childStderr.close()
    _childStdin = _FDOutputStream(fd: -1)
    _childStdout = _FDInputStream(fd: -1)
    _childStderr = _FDInputStream(fd: -1)
    return status
  }

  /// Returns the values of the corresponding variables in the child process.
  internal mutating func _runTestInChild(
    _ testSuite: TestSuite,
    _ testName: String,
    parameter: Int?
  ) -> (anyExpectFailed: Bool, seenExpectCrash: Bool,
        status: ProcessTerminationStatus?,
        crashStdout: [String], crashStderr: [String]) {
    if _pid <= 0 {
      _spawnChild()
    }

    print("\(testSuite.name);\(testName)", terminator: "", to: &_childStdin)
    if let parameter = parameter {
      print(";", terminator: "", to: &_childStdin)
      print(parameter, terminator: "", to: &_childStdin)
    }
    print("", to: &_childStdin)

    let currentTest = testSuite._testByName(testName)
    if let stdinText = currentTest.stdinText {
      print(stdinText, terminator: "", to: &_childStdin)
    }
    if currentTest.stdinEndsWithEOF {
      _childStdin.close()
    }

    var readfds = _stdlib_fd_set()
    var writefds = _stdlib_fd_set()
    var errorfds = _stdlib_fd_set()
    var stdoutSeenCrashDelimiter = false
    var stderrSeenCrashDelimiter = false
    var stdoutEnd = false
    var stderrEnd = false
    var capturedCrashStdout: [String] = []
    var capturedCrashStderr: [String] = []
    var anyExpectFailedInChild = false
    while !((_childStdout.isEOF && _childStderr.isEOF) ||
      (stdoutEnd && stderrEnd)) {

      readfds.zero()
      errorfds.zero()
      if !_childStdout.isEOF {
        readfds.set(_childStdout.fd)
        errorfds.set(_childStdout.fd)
      }
      if !_childStderr.isEOF {
        readfds.set(_childStderr.fd)
        errorfds.set(_childStderr.fd)
      }
      var ret: CInt
      repeat {
        ret = _stdlib_select(&readfds, &writefds, &errorfds, nil)
      } while ret == -1  &&  errno == EINTR
      if ret <= 0 {
        fatalError("select() returned an error")
      }
      if readfds.isset(_childStdout.fd) || errorfds.isset(_childStdout.fd) {
        _childStdout.read()
        while var line = _childStdout.getline() {
          if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
            let controlMessage =
                line[index..<line.endIndex]._split(separator: ";")
            switch controlMessage[1] {
            case "expectCrash":
              stdoutSeenCrashDelimiter = true
              anyExpectFailedInChild = controlMessage[2] == "true"
            case "end":
              stdoutEnd = true
              anyExpectFailedInChild = controlMessage[2] == "true"
            default:
              fatalError("unexpected message")
            }
            line = line[line.startIndex..<index]
            if line.isEmpty {
              continue
            }
          }
          if stdoutSeenCrashDelimiter {
            capturedCrashStdout.append(line)
          }
          print("stdout>>> \(line)")
        }
        continue
      }
      if readfds.isset(_childStderr.fd) || errorfds.isset(_childStderr.fd) {
        _childStderr.read()
        while var line = _childStderr.getline() {
          if let index = findSubstring(line, _stdlibUnittestStreamPrefix) {
            let controlMessage =
                line[index..<line.endIndex]._split(separator: ";")
            switch controlMessage[1] {
            case "expectCrash":
              stderrSeenCrashDelimiter = true
            case "end":
              stderrEnd = true
            default:
              fatalError("unexpected message")
            }
            line = line[line.startIndex..<index]
            if line.isEmpty {
              continue
            }
          }
          if stderrSeenCrashDelimiter {
            capturedCrashStderr.append(line)
            if findSubstring(line, _crashedPrefix) != nil {
              line = "OK: saw expected \"\(line.lowercased())\""
            }
          }
          print("stderr>>> \(line)")
        }
        continue
      }
    }

    // Check if the child has sent us "end" markers for the current test.
    if stdoutEnd && stderrEnd {
      testSuite._testByName(testName)
      var status: ProcessTerminationStatus? = nil
      if !testSuite._testByName(testName).canReuseChildProcessAfterTest {
        status = _waitForChild()
        switch status! {
        case .exit(0):
          status = nil
        default:
          ()
        }
      }
      return (
        anyExpectFailedInChild,
        stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
        capturedCrashStdout, capturedCrashStderr)
    }

    // We reached EOF on stdout and stderr and we did not see "end" markers, so
    // it looks like child crashed (of course it could have closed the file
    // descriptors, but we assume it did not, since it prevent further
    // communication with the parent).
    let status = _waitForChild()
    return (
      anyExpectFailedInChild,
      stdoutSeenCrashDelimiter || stderrSeenCrashDelimiter, status,
      capturedCrashStdout, capturedCrashStderr)
  }

  internal enum _TestStatus {
    case skip([TestRunPredicate])
    case pass
    case fail
    case uxPass
    case xFail
  }

  internal mutating func runOneTest(
    fullTestName: String,
    testSuite: TestSuite,
    test t: TestSuite._Test,
    testParameter: Int?
  ) -> _TestStatus {
    let activeSkips = t.getActiveSkipPredicates()
    if !activeSkips.isEmpty {
      return .skip(activeSkips)
    }

    let activeXFails = t.getActiveXFailPredicates()
    let expectXFail = !activeXFails.isEmpty
    let activeXFailsText = expectXFail ? " (XFAIL: \(activeXFails))" : ""
    print("[ RUN      ] \(fullTestName)\(activeXFailsText)")

    var expectCrash = false
    var childTerminationStatus: ProcessTerminationStatus? = nil
    var crashStdout: [String] = []
    var crashStderr: [String] = []
    if _runTestsInProcess {
      if t.stdinText != nil {
        print("The test \(fullTestName) requires stdin input and can't be run in-process, marking as failed")
        _anyExpectFailed = true
      } else {
        _anyExpectFailed = false
        testSuite._runTest(name: t.name, parameter: testParameter)
      }
    } else {
      (_anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
       crashStderr) =
        _runTestInChild(testSuite, t.name, parameter: testParameter)
    }

    // Determine if the test passed, not taking XFAILs into account.
    var testPassed = false
    switch (childTerminationStatus, expectCrash) {
    case (.none, false):
      testPassed = !_anyExpectFailed

    case (.none, true):
      testPassed = false
      print("expecting a crash, but the test did not crash")

    case (.some(_), false):
      testPassed = false
      print("the test crashed unexpectedly")

    case (.some(_), true):
      testPassed = !_anyExpectFailed
    }
    if testPassed && t.crashOutputMatches.count > 0 {
      // If we still think that the test passed, check if the crash
      // output matches our expectations.
      let crashOutput = crashStdout + crashStderr
      for expectedSubstring in t.crashOutputMatches {
        var found = false
        for s in crashOutput {
          if findSubstring(s, expectedSubstring) != nil {
            found = true
            break
          }
        }
        if !found {
          print("did not find expected string after crash: \(expectedSubstring.debugDescription)")
          testPassed = false
        }
      }
    }

    // Apply XFAILs.
    switch (testPassed, expectXFail) {
    case (true, false):
      return .pass

    case (true, true):
      return .uxPass

    case (false, false):
      return .fail

    case (false, true):
      return .xFail
    }
  }

  mutating func run() {
    if let filter = _filter {
      print("StdlibUnittest: using filter: \(filter)")
    }
    for testSuite in _allTestSuites {
      var uxpassedTests: [String] = []
      var failedTests: [String] = []
      var skippedTests: [String] = []
      for t in testSuite._tests {
        for testParameter in t.parameterValues {
          var testName = t.name
          if let testParameter = testParameter {
            testName += "/"
            testName += String(testParameter)
          }
          let fullTestName = "\(testSuite.name).\(testName)"
          if let filter = _filter
            where findSubstring(fullTestName, filter) == nil {

            continue
          }

          switch runOneTest(
            fullTestName: fullTestName,
            testSuite: testSuite,
            test: t,
            testParameter: testParameter
          ) {
          case .skip(let activeSkips):
            skippedTests.append(testName)
            print("[ SKIP     ] \(fullTestName) (skip: \(activeSkips))")

          case .pass:
            print("[       OK ] \(fullTestName)")

          case .uxPass:
            uxpassedTests.append(testName)
            print("[   UXPASS ] \(fullTestName)")

          case .fail:
            failedTests.append(testName)
            print("[     FAIL ] \(fullTestName)")

          case .xFail:
            print("[    XFAIL ] \(fullTestName)")
          }
        }
      }

      if !uxpassedTests.isEmpty || !failedTests.isEmpty {
        print("\(testSuite.name): Some tests failed, aborting")
        print("UXPASS: \(uxpassedTests)")
        print("FAIL: \(failedTests)")
        print("SKIP: \(skippedTests)")
        if !uxpassedTests.isEmpty {
          _printDebuggingAdvice(uxpassedTests[0])
        }
        if !failedTests.isEmpty {
          _printDebuggingAdvice(failedTests[0])
        }
        _testSuiteFailedCallback()
      } else {
        print("\(testSuite.name): All tests passed")
      }
    }
  }
}

// Track repeated calls to runAllTests() and/or runNoTests().
// Complain if a file runs no tests without calling runNoTests().
struct PersistentState {
  static var runAllTestsWasCalled: Bool = false
  static var runNoTestsWasCalled: Bool = false
  static var ranSomething: Bool = false
  static var complaintInstalled = false

  static func complainIfNothingRuns() {
    if !complaintInstalled {
      complaintInstalled = true
      atexit {
        if !PersistentState.ranSomething {
          print("Ran no tests and runNoTests() was not called. Aborting. ")
          print("Did you forget to call runAllTests()?")
          _testSuiteFailedCallback()
        }
      }
    }
  }
}


// Call runNoTests() if you want to deliberately run no tests.
public func runNoTests() {
  if PersistentState.runAllTestsWasCalled {
    print("runNoTests() called after runAllTests(). Aborting.")
    _testSuiteFailedCallback()
    return
  }
  if PersistentState.runNoTestsWasCalled {
    print("runNoTests() called twice. Aborting.")
    _testSuiteFailedCallback()
    return
  }
  PersistentState.runNoTestsWasCalled = true
  PersistentState.ranSomething = true
}

public func runAllTests() {
  if PersistentState.runNoTestsWasCalled {
    print("runAllTests() called after runNoTests(). Aborting.")
    _testSuiteFailedCallback()
    return
  }
  if PersistentState.runAllTestsWasCalled {
    print("runAllTests() called twice. Aborting.")
    _testSuiteFailedCallback()
    return
  }
  PersistentState.runAllTestsWasCalled = true
  PersistentState.ranSomething = true

#if _runtime(_ObjC)
  autoreleasepool {
    _stdlib_initializeReturnAutoreleased()
  }
#endif

  let _isChildProcess: Bool =
    Process.arguments.contains("--stdlib-unittest-run-child")

  if _isChildProcess {
    _childProcess()
  } else {
    var runTestsInProcess: Bool = false
    var filter: String? = nil
    var args = [String]()
    var i = 0
    i += 1 // Skip the name of the executable.
    while i < Process.arguments.count {
      let arg = Process.arguments[i]
      if arg == "--stdlib-unittest-in-process" {
        runTestsInProcess = true
        i += 1
        continue
      }
      if arg == "--stdlib-unittest-filter" {
        filter = Process.arguments[i + 1]
        i += 2
        continue
      }
      if arg == "--help" {
        let message =
"optional arguments:\n" +
"--stdlib-unittest-in-process\n" +
"                        run tests in-process without intercepting crashes.\n" +
"                        Useful for running under a debugger.\n" +
"--stdlib-unittest-filter FILTER-STRING\n" +
"                        only run tests whose names contain FILTER-STRING as\n" +
"                        a substring."
        print(message)
        return
      }

      // Pass through unparsed arguments to the child process.
      args.append(Process.arguments[i])

      i += 1
    }

    var parent = _ParentProcess(
      runTestsInProcess: runTestsInProcess, args: args, filter: filter)
    parent.run()
  }
}

public final class TestSuite {
  public init(_ name: String) {
    self.name = name
    _precondition(
      _testNameToIndex[name] == nil,
      "test suite with the same name already exists")
    _allTestSuites.append(self)
    _testSuiteNameToIndex[name] = _allTestSuites.count - 1
    PersistentState.complainIfNothingRuns()
  }

  public func test(
    _ name: String,
    file: String = #file, line: UInt = #line,
    _ testFunction: () -> Void
  ) {
    _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
    .code(testFunction)
  }

  public func test(
    _ name: String, file: String = #file, line: UInt = #line
  ) -> _TestBuilder {
    return _TestBuilder(testSuite: self, name: name, loc: SourceLoc(file, line))
  }

  public func setUp(_ code: () -> Void) {
    _precondition(_testSetUpCode == nil, "set-up code already set")
    _testSetUpCode = code
  }

  public func tearDown(_ code: () -> Void) {
    _precondition(_testTearDownCode == nil, "tear-down code already set")
    _testTearDownCode = code
  }

  func _runTest(name testName: String, parameter: Int?) {
    PersistentState.ranSomething = true
    for r in _allResettables {
      r.reset()
    }
    LifetimeTracked.instances = 0
    if let f = _testSetUpCode {
      f()
    }
    let test = _testByName(testName)
    switch test.code {
    case .single(let code):
      precondition(
        parameter == nil,
        "can't pass parameters to non-parameterized tests")
      code()
    case .parameterized(code: let code, _):
      code(parameter!)
    }
    if let f = _testTearDownCode {
      f()
    }
    expectEqual(
      0, LifetimeTracked.instances, "leaked LifetimeTracked instances:",
      file: test.testLoc.file, line: test.testLoc.line)
  }

  func _testByName(_ testName: String) -> _Test {
    return _tests[_testNameToIndex[testName]!]
  }

  internal enum _TestCode {
    case single(code: () -> Void)
    case parameterized(code: (Int) -> Void, count: Int)
  }

  internal struct _Test {
    let name: String
    let testLoc: SourceLoc
    let xfail: [TestRunPredicate]
    let skip: [TestRunPredicate]
    let stdinText: String?
    let stdinEndsWithEOF: Bool
    let crashOutputMatches: [String]
    let code: _TestCode

    /// Whether the test harness should stop reusing the child process after
    /// running this test.
    var canReuseChildProcessAfterTest: Bool {
      return stdinText == nil
    }

    func getActiveXFailPredicates() -> [TestRunPredicate] {
      return xfail.filter { $0.evaluate() }
    }

    func getActiveSkipPredicates() -> [TestRunPredicate] {
      return skip.filter { $0.evaluate() }
    }

    var parameterValues: [Int?] {
      switch code {
      case .single:
        return [nil]
      case .parameterized(code: _, count: let count):
        return (0..<count).map { $0 }
      }
    }
  }

  public struct _TestBuilder {
    let _testSuite: TestSuite
    var _name: String
    var _data: _Data = _Data()

    internal final class _Data {
      var _xfail: [TestRunPredicate] = []
      var _skip: [TestRunPredicate] = []
      var _stdinText: String? = nil
      var _stdinEndsWithEOF: Bool = false
      var _crashOutputMatches: [String] = []
      var _testLoc: SourceLoc? = nil
    }

    init(testSuite: TestSuite, name: String, loc: SourceLoc) {
      _testSuite = testSuite
      _name = name
      _data._testLoc = loc
    }

    public func xfail(_ predicate: TestRunPredicate) -> _TestBuilder {
      _data._xfail.append(predicate)
      return self
    }

    public func skip(_ predicate: TestRunPredicate) -> _TestBuilder {
      _data._skip.append(predicate)
      return self
    }

    public func stdin(_ stdinText: String, eof: Bool = false) -> _TestBuilder {
      _data._stdinText = stdinText
      _data._stdinEndsWithEOF = eof
      return self
    }

    public func crashOutputMatches(_ string: String) -> _TestBuilder {
      _data._crashOutputMatches.append(string)
      return self
    }

    internal func _build(_ testCode: _TestCode) {
      _testSuite._tests.append(
        _Test(
          name: _name, testLoc: _data._testLoc!, xfail: _data._xfail,
          skip: _data._skip,
          stdinText: _data._stdinText,
          stdinEndsWithEOF: _data._stdinEndsWithEOF,
          crashOutputMatches: _data._crashOutputMatches,
          code: testCode))
      _testSuite._testNameToIndex[_name] = _testSuite._tests.count - 1
    }

    public func code(_ testFunction: () -> Void) {
      _build(.single(code: testFunction))
    }

    public func forEach<Data>(
      in parameterSets: [Data],
      testFunction: (Data) -> Void
    ) {
      _build(.parameterized(
        code: { (i: Int) in testFunction(parameterSets[i]) },
        count: parameterSets.count))
    }
  }

  var name: String
  var _tests: [_Test] = []

  /// Code that is run before every test.
  var _testSetUpCode: (() -> Void)?

  /// Code that is run after every test.
  var _testTearDownCode: (() -> Void)?

  /// Maps test name to index in `_tests`.
  var _testNameToIndex: [String : Int] = [:]
}

#if os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
@_silgen_name("swift_stdlib_getSystemVersionPlistProperty")
func _stdlib_getSystemVersionPlistPropertyImpl(
  _ propertyName: UnsafePointer<CChar>) -> UnsafePointer<CChar>

func _stdlib_getSystemVersionPlistProperty(_ propertyName: String) -> String? {
  let cs = _stdlib_getSystemVersionPlistPropertyImpl(propertyName)
  return (cs != nil) ? String(cString: cs) : nil
}
#endif

public enum OSVersion : CustomStringConvertible {
  case osx(major: Int, minor: Int, bugFix: Int)
  case iOS(major: Int, minor: Int, bugFix: Int)
  case tvOS(major: Int, minor: Int, bugFix: Int)
  case watchOS(major: Int, minor: Int, bugFix: Int)
  case iOSSimulator
  case tvOSSimulator
  case watchOSSimulator
  case linux
  case freeBSD

  public var description: String {
    switch self {
    case osx(let major, let minor, let bugFix):
      return "OS X \(major).\(minor).\(bugFix)"
    case iOS(let major, let minor, let bugFix):
      return "iOS \(major).\(minor).\(bugFix)"
    case tvOS(let major, let minor, let bugFix):
      return "TVOS \(major).\(minor).\(bugFix)"
    case watchOS(let major, let minor, let bugFix):
      return "watchOS \(major).\(minor).\(bugFix)"
    case iOSSimulator:
      return "iOSSimulator"
    case tvOSSimulator:
      return "TVOSSimulator"
    case watchOSSimulator:
      return "watchOSSimulator"
    case linux:
      return "Linux"
    case freeBSD:
      return "FreeBSD"
    }
  }
}

func _parseDottedVersion(_ s: String) -> [Int] {
  return Array(s._split(separator: ".").lazy.map { Int($0)! })
}

public func _parseDottedVersionTriple(_ s: String) -> (Int, Int, Int) {
  var array = _parseDottedVersion(s)
  if array.count >= 4 {
    fatalError("unexpected version")
  }
  return (
    array.count >= 1 ? array[0] : 0,
    array.count >= 2 ? array[1] : 0,
    array.count >= 3 ? array[2] : 0)
}

func _getOSVersion() -> OSVersion {
#if os(iOS) && (arch(i386) || arch(x86_64))
  // On simulator, the plist file that we try to read turns out to be host's
  // plist file, which indicates OS X.
  //
  // FIXME: how to get the simulator version *without* UIKit?
  return .iOSSimulator
#elseif os(tvOS) && (arch(i386) || arch(x86_64))
  return .tvOSSimulator
#elseif os(watchOS) && (arch(i386) || arch(x86_64))
  return .watchOSSimulator
#elseif os(Linux)
  return .linux
#elseif os(FreeBSD)
  return .freeBSD
#else
  let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")!
  let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion)
  #if os(OSX)
  return .osx(major: major, minor: minor, bugFix: bugFix)
  #elseif os(iOS)
  return .iOS(major: major, minor: minor, bugFix: bugFix)
  #elseif os(tvOS)
  return .tvOS(major: major, minor: minor, bugFix: bugFix)
  #elseif os(watchOS)
  return .watchOS(major: major, minor: minor, bugFix: bugFix)
  #else
  fatalError("could not determine OS version")
  #endif
#endif
}

var _runningOSVersion: OSVersion = _getOSVersion()
var _overrideOSVersion: OSVersion? = nil

/// Override the OS version for testing.
public func _setOverrideOSVersion(_ v: OSVersion) {
  _overrideOSVersion = v
}

func _getRunningOSVersion() -> OSVersion {
  // Allow overriding the OS version for testing.
  return _overrideOSVersion ?? _runningOSVersion
}

public enum TestRunPredicate : CustomStringConvertible {
  case custom(() -> Bool, reason: String)

  case always(/*reason:*/ String)
  case never

  case osxAny(/*reason:*/ String)
  case osxMajor(Int, reason: String)
  case osxMinor(Int, Int, reason: String)
  case osxMinorRange(Int, Range<Int>, reason: String)
  case osxBugFix(Int, Int, Int, reason: String)
  case osxBugFixRange(Int, Int, Range<Int>, reason: String)

  case iOSAny(/*reason:*/ String)
  case iOSMajor(Int, reason: String)
  case iOSMinor(Int, Int, reason: String)
  case iOSMinorRange(Int, Range<Int>, reason: String)
  case iOSBugFix(Int, Int, Int, reason: String)
  case iOSBugFixRange(Int, Int, Range<Int>, reason: String)

  case iOSSimulatorAny(/*reason:*/ String)

  case tvOSAny(/*reason:*/ String)
  case tvOSMajor(Int, reason: String)
  case tvOSMinor(Int, Int, reason: String)
  case tvOSMinorRange(Int, Range<Int>, reason: String)
  case tvOSBugFix(Int, Int, Int, reason: String)
  case tvOSBugFixRange(Int, Int, Range<Int>, reason: String)

  case tvOSSimulatorAny(/*reason:*/ String)

  case watchOSAny(/*reason:*/ String)
  case watchOSMajor(Int, reason: String)
  case watchOSMinor(Int, Int, reason: String)
  case watchOSMinorRange(Int, Range<Int>, reason: String)
  case watchOSBugFix(Int, Int, Int, reason: String)
  case watchOSBugFixRange(Int, Int, Range<Int>, reason: String)

  case watchOSSimulatorAny(/*reason:*/ String)

  case linuxAny(reason: String)

  case freeBSDAny(reason: String)

  case objCRuntime(/*reason:*/ String)
  case nativeRuntime(/*reason:*/ String)

  public var description: String {
    switch self {
    case custom(_, let reason):
      return "Custom(reason: \(reason))"

    case always(let reason):
      return "Always(reason: \(reason))"
    case never:
      return ""

    case osxAny(let reason):
      return "osx(*, reason: \(reason))"
    case osxMajor(let major, let reason):
      return "osx(\(major).*, reason: \(reason))"
    case osxMinor(let major, let minor, let reason):
      return "osx(\(major).\(minor), reason: \(reason))"
    case osxMinorRange(let major, let minorRange, let reason):
      return "osx(\(major).[\(minorRange)], reason: \(reason))"
    case osxBugFix(let major, let minor, let bugFix, let reason):
      return "osx(\(major).\(minor).\(bugFix), reason: \(reason))"
    case osxBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "osx(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case iOSAny(let reason):
      return "iOS(*, reason: \(reason))"
    case iOSMajor(let major, let reason):
      return "iOS(\(major).*, reason: \(reason))"
    case iOSMinor(let major, let minor, let reason):
      return "iOS(\(major).\(minor), reason: \(reason))"
    case iOSMinorRange(let major, let minorRange, let reason):
      return "iOS(\(major).[\(minorRange)], reason: \(reason))"
    case iOSBugFix(let major, let minor, let bugFix, let reason):
      return "iOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case iOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "iOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case iOSSimulatorAny(let reason):
      return "iOSSimulatorAny(*, reason: \(reason))"

    case tvOSAny(let reason):
      return "tvOS(*, reason: \(reason))"
    case tvOSMajor(let major, let reason):
      return "tvOS(\(major).*, reason: \(reason))"
    case tvOSMinor(let major, let minor, let reason):
      return "tvOS(\(major).\(minor), reason: \(reason))"
    case tvOSMinorRange(let major, let minorRange, let reason):
      return "tvOS(\(major).[\(minorRange)], reason: \(reason))"
    case tvOSBugFix(let major, let minor, let bugFix, let reason):
      return "tvOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case tvOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "tvOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case tvOSSimulatorAny(let reason):
      return "tvOSSimulatorAny(*, reason: \(reason))"

    case watchOSAny(let reason):
      return "watchOS(*, reason: \(reason))"
    case watchOSMajor(let major, let reason):
      return "watchOS(\(major).*, reason: \(reason))"
    case watchOSMinor(let major, let minor, let reason):
      return "watchOS(\(major).\(minor), reason: \(reason))"
    case watchOSMinorRange(let major, let minorRange, let reason):
      return "watchOS(\(major).[\(minorRange)], reason: \(reason))"
    case watchOSBugFix(let major, let minor, let bugFix, let reason):
      return "watchOS(\(major).\(minor).\(bugFix), reason: \(reason))"
    case watchOSBugFixRange(let major, let minor, let bugFixRange, let reason):
      return "watchOS(\(major).\(minor).[\(bugFixRange)], reason: \(reason))"

    case watchOSSimulatorAny(let reason):
      return "watchOSSimulatorAny(*, reason: \(reason))"

    case linuxAny(reason: let reason):
      return "linuxAny(*, reason: \(reason))"

    case freeBSDAny(reason: let reason):
      return "freeBSDAny(*, reason: \(reason))"

    case objCRuntime(let reason):
      return "Objective-C runtime, reason: \(reason))"
    case nativeRuntime(let reason):
      return "Native runtime (no ObjC), reason: \(reason))"
    }
  }

  public func evaluate() -> Bool {
    switch self {
    case custom(let predicate, _):
      return predicate()

    case always:
      return true
    case never:
      return false

    case osxAny:
      switch _getRunningOSVersion() {
      case .osx:
        return true
      default:
        return false
      }

    case osxMajor(let major, _):
      switch _getRunningOSVersion() {
      case .osx(major, _, _):
        return true
      default:
        return false
      }

    case osxMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, _):
        return true
      default:
        return false
      }

    case osxMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .osx(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case osxBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, bugFix):
        return true
      default:
        return false
      }

    case osxBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .osx(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case iOSAny:
      switch _getRunningOSVersion() {
      case .iOS:
        return true
      default:
        return false
      }

    case iOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .iOS(major, _, _):
        return true
      default:
        return false
      }

    case iOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, _):
        return true
      default:
        return false
      }

    case iOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .iOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case iOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case iOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .iOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case iOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .iOSSimulator:
        return true
      default:
        return false
      }

    case tvOSAny:
      switch _getRunningOSVersion() {
      case .tvOS:
        return true
      default:
        return false
      }

    case tvOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, _, _):
        return true
      default:
        return false
      }

    case tvOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, _):
        return true
      default:
        return false
      }

    case tvOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case tvOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case tvOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .tvOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case tvOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .tvOSSimulator:
        return true
      default:
        return false
      }

    case watchOSAny:
      switch _getRunningOSVersion() {
      case .watchOS:
        return true
      default:
        return false
      }

    case watchOSMajor(let major, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, _, _):
        return true
      default:
        return false
      }

    case watchOSMinor(let major, let minor, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, _):
        return true
      default:
        return false
      }

    case watchOSMinorRange(let major, let minorRange, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, let runningMinor, _):
        return minorRange.contains(runningMinor)
      default:
        return false
      }

    case watchOSBugFix(let major, let minor, let bugFix, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, bugFix):
        return true
      default:
        return false
      }

    case watchOSBugFixRange(let major, let minor, let bugFixRange, _):
      switch _getRunningOSVersion() {
      case .watchOS(major, minor, let runningBugFix):
        return bugFixRange.contains(runningBugFix)
      default:
        return false
      }

    case watchOSSimulatorAny:
      switch _getRunningOSVersion() {
      case .watchOSSimulator:
        return true
      default:
        return false
      }

    case linuxAny:
      switch _getRunningOSVersion() {
      case .linux:
        return true
      default:
        return false
      }

    case freeBSDAny:
      switch _getRunningOSVersion() {
      case .freeBSD:
        return true
      default:
        return false
      }

    case objCRuntime:
#if _runtime(_ObjC)
      return true
#else
      return false
#endif

    case nativeRuntime:
#if _runtime(_ObjC)
      return false
#else
      return true
#endif
    }
  }
}

//
// Semantic tests for protocol conformance
//

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Equatable`, using `oracle` to generate equality
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkEquatable<
  Instances: Collection where Instances.Iterator.Element : Equatable
>(
  _ instances: Instances,
  oracle: (Instances.Index, Instances.Index) -> Bool,
  ${TRACE}
) {
  for i in instances.indices {
    expectTrue(oracle(i, i), "bad oracle: broken reflexivity at index \(i)")
    let x = instances[i]
    // Reflexivity
    expectEqual(x, x, ${trace})
    for j in instances.indices {
      let predictedXY = oracle(i, j)
      expectEqual(
        predictedXY, oracle(j, i),
        "bad oracle: broken symmetry between indices \(i), \(j)")
      
      let y = instances[j]

      let xy = x == y
      expectEqual(predictedXY, xy, ${trace})

      // Not-equal is an inverse of equal
      expectNotEqual(xy, x != y, ${trace})
      
      // Symmetry
      expectEqual(xy, y == x, ${trace})
      
      for k in instances.indices {
        let z = instances[k]
        // Transitivity
        if xy && y == z {
          expectTrue(
            oracle(i, k),
            "bad oracle: broken transitivity at indices \(i), \(j), \(k)")
          expectEqual(x, z, ${trace})
        }
      }
    }
  }
}

public func checkEquatable<T : Equatable>(
  _ expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
  checkEquatable(
    [lhs, rhs],
    oracle: { expectedEqual || $0 == $1 }, ${trace}, showFrame: false)
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Hashable`, using `equalityOracle` to generate
/// equality expectations from pairs of positions in `instances`.
public func checkHashable<
  Instances: Collection where Instances.Iterator.Element : Hashable
>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  ${TRACE}
) {
  checkEquatable(instances, oracle: equalityOracle, ${trace})
  
  for x in instances {
    for y in instances {
      if x == y {
        expectEqual(x.hashValue, y.hashValue, ${trace})
      }
    }
  }
}

public func checkHashable<T : Hashable>(
  _ expectedEqual: Bool, _ lhs: T, _ rhs: T, ${TRACE}
) {
  checkHashable(
    [lhs, rhs], equalityOracle: { expectedEqual || $0 == $1 }, ${trace})
}

% for inc, protocol, successor, end in (
%  ('inc', '_Incrementable', 'successor', 'end'),
%  ('dec', 'BidirectionalIndex', 'predecessor', 'start')):

/// Test that the elements of `instances` satisfy
/// ${'some of ' if inc == 'dec' else ''}the semantic
/// requirements of `${protocol}`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: ${'''`endIndex` is reachable from all 
///   elements of `instances`.''' if inc == 'inc' else '''all
///   elements of `instances` are reachable from `startIndex`.'''}
public func check${inc.capitalize()}rementable<
  Instances: Collection
  where Instances.Iterator.Element : ${protocol}
>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  ${end}Index: Instances.Iterator.Element, ${TRACE}
) {
  checkEquatable(instances, oracle: equalityOracle, ${trace})
  for i in instances {
    if i != ${end}Index {
      let next = i.${successor}()
      // ${successor} gets us a new index value
      expectNotEqual(i, next, ${trace})

      // Which is the same as if we apply _${successor}InPlace
      var j = i
      j._${successor}InPlace()
      expectEqual(j, next, ${trace})
    }
  }
}
%end

public enum ExpectedComparisonResult {
  case lt, eq, gt

  public func isLT() -> Bool {
    return self == .lt
  }

  public func isEQ() -> Bool {
    return self == .eq
  }

  public func isGT() -> Bool {
    return self == .gt
  }

  public func isLE() -> Bool {
    return isLT() || isEQ()
  }

  public func isGE() -> Bool {
    return isGT() || isEQ()
  }

  public func isNE() -> Bool {
    return !isEQ()
  }

  public func flip() -> ExpectedComparisonResult {
    switch self {
    case .lt:
      return .gt
    case .eq:
      return .eq
    case .gt:
      return .lt
    }
  }
}

extension ExpectedComparisonResult : CustomStringConvertible {
  public var description: String {
    switch self {
    case .lt:
      return "<"
    case .eq:
      return "=="
    case .gt:
      return ">"
    }
  }
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Comparable`, using `oracle` to generate comparison
/// expectations from pairs of positions in `instances`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkComparable<
  Instances: Collection where Instances.Iterator.Element : Comparable
>(
  _ instances: Instances,
  oracle: (Instances.Index, Instances.Index) -> ExpectedComparisonResult,
  ${TRACE}
) {
  // Also checks that equality is consistent with comparison and that
  // the oracle obeys the equality laws
  checkEquatable(instances, oracle: { oracle($0, $1).isEQ() }, ${trace})
  
  for i in instances.indices {
    let x = instances[i]

    expectFalse(x < x, ${trace})
    expectFalse(x > x, ${trace})
    expectTrue(x <= x, ${trace})
    expectTrue(x >= x, ${trace})
    
    for j in instances.indices where i != j {
      let y = instances[j]
      
      let expected = oracle(i, j)
      
      expectEqual(
        expected.flip(), oracle(j, i),
        "bad oracle: missing antisymmetry: "
        + "(\(String(reflecting: i)), \(String(reflecting: j)))",
        stackTrace: ${stackTrace})
      
      expectEqual(expected.isLT(), x < y, ${trace})
      expectEqual(expected.isLE(), x <= y, ${trace})
      expectEqual(expected.isGE(), x >= y, ${trace})
      expectEqual(expected.isGT(), x > y, ${trace})
      
      for k in instances.indices {
        let expected2 = oracle(j, k)
        if expected == expected2 {
          expectEqual(
            expected, oracle(i, k),
            "bad oracle: missing transitivity "
            + "(\(String(reflecting: i)), \(String(reflecting: j)), "
            + "\(String(reflecting: k)))", stackTrace: ${stackTrace})
        }
      }
    }
  }
}

public func checkComparable<T : Comparable>(
  _ expected: ExpectedComparisonResult, _ lhs: T, _ rhs: T, ${TRACE}
) {
  checkComparable(
    [lhs, rhs],
    oracle: { [[ .eq, expected], [ expected.flip(), .eq]][$0][$1] },
    ${trace})
}


/// Test that the elements of `instances` satisfy the semantic
/// requirements of `Strideable`, using `advanceOracle` and
/// 'distanceOracle' to generate expectations about the results of
/// `advanced(by:)` and `distance(to:)` from pairs of positions in
/// `instances` and `strides`.
///
/// - Note: `oracle` is also checked for conformance to the
///   laws.
public func checkStrideable<
  Instances: Collection, Strides: Collection
  where
  Instances.Iterator.Element : Strideable,
  Strides.Iterator.Element == Instances.Iterator.Element.Stride
>(
  _ instances: Instances, strides: Strides,
  distanceOracle:
    (Instances.Index, Instances.Index) -> Strides.Iterator.Element,
  advanceOracle:
    (Instances.Index, Strides.Index) -> Instances.Iterator.Element,
  ${TRACE}
) {
  checkComparable(
    instances,
    oracle: {
      let d = distanceOracle($1, $0);
      return d < 0 ? .lt : d == 0 ? .eq : .gt
    },
    ${trace})
  
  for i in instances.indices {
    let x = instances[i]
    expectEqual(x, x.advanced(by: 0))
    
    for j in strides.indices {
      let y = strides[j]
      expectEqual(advanceOracle(i, j), x.advanced(by: y))
    }

    for j in instances.indices {
      let y = instances[j]
      expectEqual(distanceOracle(i, j), x.distance(to: y))
    }
  }
}

public struct CollectionMisuseResiliencyChecks {
  public enum FailureKind {
    case none
    case trap
    case expectationFailure
  }

  public var callNextOnExhaustedGenerator: Bool = true
  public var creatingOutOfBoundsIndicesBehavior: FailureKind = .trap
  public var subscriptOnOutOfBoundsIndicesBehavior: FailureKind = .trap
  public var subscriptRangeOnOutOfBoundsRangesBehavior: FailureKind = .trap

  public static var all: CollectionMisuseResiliencyChecks {
    return CollectionMisuseResiliencyChecks()
  }

  public static var none: CollectionMisuseResiliencyChecks {
    return CollectionMisuseResiliencyChecks(
      callNextOnExhaustedGenerator: false,
      creatingOutOfBoundsIndicesBehavior: .none,
      subscriptOnOutOfBoundsIndicesBehavior: .none,
      subscriptRangeOnOutOfBoundsRangesBehavior: .none)
  }
}

internal func _checkIncrementalAdvance<
  Instances : Collection
  where
  Instances.Iterator.Element : ForwardIndex
>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  limit: Instances.Iterator.Element,
  sign: Instances.Iterator.Element.Distance, // 1 or -1
  next: (Instances.Iterator.Element) -> Instances.Iterator.Element,
  ${TRACE}
) {
  for i in instances {
    let d = sign > 0 ? i.distance(to: limit) : -limit.distance(to: i)

    var offset: Instances.Iterator.Element.Distance = 0
    for _ in 0...(d * sign).toIntMax() {
      let j = i.advanced(by: offset)
      let k = i.advanced(by: offset + sign, limit: limit)
      let jAtLimit = offset == d
      if jAtLimit {
        expectEqual(limit, j, ${trace})
      }
      expectEqual(jAtLimit ? j : next(j), k, ${trace})
      offset += sign
    }
  }
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `ForwardIndex`, using `equalityOracle` to
/// generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition: `endIndex` is reachable from all elements of
///   `instances`
public func checkForwardIndex<
  Instances : Collection
  where
  Instances.Iterator.Element : ForwardIndex
>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  endIndex: Instances.Iterator.Element, ${TRACE}
) {
  typealias Index = Instances.Iterator.Element
  
  checkIncrementable(
    instances, equalityOracle: equalityOracle, endIndex: endIndex, ${trace})

  _checkIncrementalAdvance(
    instances, equalityOracle: equalityOracle, limit: endIndex,
    sign: 1, next: { $0.successor() }, ${trace})
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `BidirectionalIndex`, using `equalityOracle`
/// to generate equality expectations from pairs of positions in
/// `instances`.
///
/// - Precondition:
///   - all elements of `instances` are reachable from `startIndex`.
///   - `endIndex` is reachable from all elements of `instances`.
public func checkBidirectionalIndex<
  Instances: Collection
  where
  Instances.Iterator.Element : BidirectionalIndex
>(
  _ instances: Instances,
  equalityOracle: (Instances.Index, Instances.Index) -> Bool,
  startIndex: Instances.Iterator.Element, 
  endIndex: Instances.Iterator.Element,
  ${TRACE}
) {
  typealias Index = Instances.Iterator.Element

  checkForwardIndex(
    instances, equalityOracle: equalityOracle, endIndex: endIndex)

  checkDecrementable(
    instances, equalityOracle: equalityOracle, startIndex: startIndex, ${trace})

  _checkIncrementalAdvance(
    instances, equalityOracle: equalityOracle, limit: startIndex,
    sign: -1, next: { $0.predecessor() }, ${trace})
}

/// Test that the elements of `instances` satisfy the semantic
/// requirements of `RandomAccessIndex`, using 
/// `advanceOracle` and 'distanceOracle' to generate expectations
/// about the results of `advanced(by:)` and `distance(to:)` from pairs of
/// positions in `instances` and `distances`.
///
/// - Precondition:
///   - all elements of `instances` are reachable from `startIndex`.
///   - `endIndex` is reachable from all elements of `instances`.
public func checkRandomAccessIndex<
  Instances : Collection, Distances : Collection
  where
  Instances.Iterator.Element : RandomAccessIndex,
  Distances.Iterator.Element == Instances.Iterator.Element.Distance,
  Instances.Iterator.Element.Distance == Instances.Iterator.Element.Stride
>(
  _ instances: Instances, distances: Distances,
  distanceOracle:
    (Instances.Index, Instances.Index) -> Distances.Iterator.Element,
  advanceOracle:
    (Instances.Index, Distances.Index) -> Instances.Iterator.Element,
  startIndex: Instances.Iterator.Element,
  endIndex: Instances.Iterator.Element,
  ${TRACE}
) {
  checkBidirectionalIndex(
    instances, equalityOracle: { distanceOracle($0, $1) == 0 },
    startIndex: startIndex, endIndex: endIndex, ${trace})

  checkStrideable(
    instances, strides: distances,
    distanceOracle: distanceOracle,
    advanceOracle: advanceOracle, ${trace})
}

// Generate two overloads: one for Array (which will get
// picked up when the caller passes a literal), and another that
// accepts any appropriate Collection type.
% for genericParam, Element, Expected in zip(
%   ('Expected: Collection', 'Element'),
%   ('Expected.Iterator.Element', 'Element'),
%   ('Expected', 'Array<Element>')):

public func checkIterator<
  ${genericParam}, I : IteratorProtocol
  where I.Element == ${Element}
>(
  _ expected: ${Expected},
  _ iterator: I,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
  sameValue: (${Element}, ${Element}) -> Bool
) {
  // Copying a `IteratorProtocol` is allowed.
  var mutableGen = iterator
  var actual: [${Element}] = []
  while let e = mutableGen.next() {
    actual.append(e)
  }
  expectEqualSequence(
    expected, actual, ${trace}, sameValue: sameValue)

  if resiliencyChecks.callNextOnExhaustedGenerator {
    // Having returned `.None` once, a `IteratorProtocol` should not generate more
    // elements.
    for _ in 0..<10 {
      expectEmpty(mutableGen.next(), ${trace})
    }
  }
}

public func checkIterator<
  ${genericParam}, I : IteratorProtocol
  where I.Element == ${Element}, ${Element} : Equatable
>(
  _ expected: ${Expected},
  _ iterator: I,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
  checkIterator(
    expected, iterator, ${trace},
    resiliencyChecks: resiliencyChecks, showFrame: false
  ) { $0 == $1 }
}

public func checkSequence<
  ${genericParam}, S : Sequence
  where
  S.Iterator.Element == ${Element}
>(
  _ expected: ${Expected},
  _ sequence: S,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
  sameValue: (${Element}, ${Element}) -> Bool
) {
  let expectedCount: Int = numericCast(expected.count)
  checkIterator(
    expected, sequence.makeIterator(), ${trace},
    resiliencyChecks: resiliencyChecks,
    sameValue: sameValue)

  expectGE(
    expectedCount, sequence.underestimatedCount, ${trace})

  // Check that _copyContents does the right thing if we can do so
  // without destroying the sequence.
  sequence._preprocessingPass { () -> Void in 
    var count = 0
    for _ in sequence { count += 1 }
    let buf = UnsafeMutablePointer<S.Iterator.Element>(allocatingCapacity: count)
    let end = sequence._copyContents(initializing: buf)
    expectTrue(end == buf + count, "_copyContents returned the wrong value")
    var j = expected.startIndex
    for i in 0..<(end - buf) {
      expectTrue(sameValue(expected[j], buf[i]))
      j = j.successor()
    }
    buf.deinitialize(count: end - buf)
    buf.deallocateCapacity(count)
  }
}

public func checkSequence<
  ${genericParam}, S : Sequence
  where
  S.Iterator.Element == ${Element},
  S.Iterator.Element : Equatable
>(
  _ expected: ${Expected},
  _ sequence: S,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
  checkSequence(
    expected, sequence, ${trace},
    resiliencyChecks: resiliencyChecks, showFrame: false
  ) { $0 == $1 }
}

%for traversal in ['Forward', 'Bidirectional', 'RandomAccess']:

public func check${traversal}Collection<
  ${genericParam}, C : Collection
  where
  C.Iterator.Element == ${Element},
  C.Index : ${traversal}Index
%  if traversal == 'RandomAccess':
  , C.Index.Stride == C.Index.Distance
% end
>(
  _ expected: ${Expected}, _ collection: C,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all,
  sameValue: (${Element}, ${Element}) -> Bool
) {
  // A `Collection` is a multi-pass `Sequence`.
  for _ in 0..<3 {
    checkSequence(
      expected, collection, ${trace},
      resiliencyChecks: resiliencyChecks, sameValue: sameValue)
  }

  // Advances up to 1 positions without passing endIndex.  Don't use
  // advanced(by: n) to do this because it's under test here.
  let next = { $0 == collection.endIndex ? $0 : $0.successor() }

  // advances up to 5 positions without passing endIndex.  Picking a
  // small constant to avoid complexity explosion on large input
  // collections.
  let next5 = { next(next(next(next(next($0))))) }

  let partWay0 = next5(collection.startIndex)
  let partWay1 = next5(partWay0)
% if traversal == 'Forward':
  checkForwardIndex(
    collection.startIndex..<partWay0, equalityOracle: { $0 == $1 },
    endIndex: partWay1, ${trace})
% elif traversal == 'Bidirectional':
  checkBidirectionalIndex(
    partWay0..<partWay1, equalityOracle: { $0 == $1 },
    startIndex: collection.startIndex,
    endIndex: next5(partWay1), ${trace})
% else:

%   assert(traversal == 'RandomAccess')
  typealias Distance = C.Index.Distance
  let count: Distance  = collection.count
  let offset0 = min(5, count)
  let offset1 = min(10, count)
  let offset2 = min(15, count)

  let distanceCandidates: [Distance] = [
    -11, -7, -5, -3, -2, -1, 0, 1, 2, 3, 5, 7, 11]

  let distances = distanceCandidates.filter { (x: Distance) -> Bool in
    x + offset0 >= 0 && x + offset1 <= count
  }

  func nextN(_ n: C.Index.Distance, _ i: C.Index) -> C.Index {
    var i = i
    if n < 0 {
      for _ in 0 ..< -(n.toIntMax()) {
        i -= 1
      }
    }
    else {
      for _ in 0..<n.toIntMax() {
        i += 1
      }
    }
    return i
  }

  let instances = Array(partWay0..<partWay1)
  typealias Distances = [Distance]
  checkRandomAccessIndex(
    instances,
    distances: distances,
    distanceOracle: { (x:Int,y:Int) in Distance(IntMax(y - x)) },
    advanceOracle: { x,y in nextN(distances[y], instances[x]) },
    startIndex: collection.startIndex,
    endIndex: next5(partWay1), ${trace})
% end

  let expectedArray = Array(expected)

  expectEqual(
    expectedArray.count.toIntMax(), collection.count.toIntMax(), ${trace})

  for _ in 0..<3 {
    if true {
      let startIndex = collection.startIndex
      let endIndex = collection.endIndex

      for _ in collection.indices {
        expectEqual(
          startIndex, collection.startIndex,
          "Iteration should not change startIndex",
          stackTrace: ${stackTrace})
        
        expectEqual(
          endIndex, collection.endIndex,
          "Iteration should not change endIndex",
          stackTrace: ${stackTrace})
      }
    }

    var allIndices = Array(collection.indices)

    if expectedArray.count >= 2 {
      for i in 0..<allIndices.count-1 {
        let successor1 = allIndices[i].successor()
        var successor2 = allIndices[i]
        successor2 = successor2.successor()
        var successor3 = allIndices[i]
        successor3 = successor3.successor()
        for s in [ successor1, successor2, successor3 ] {
          expectEqual(allIndices[i + 1], s, ${trace})
          expectEqual(
            expectedArray[i + 1], collection[s], ${trace}, sameValue: sameValue)
        }
      }
%   if traversal == "Bidirectional":
      for i in 1..<allIndices.count {
        let predecessor1 = allIndices[i].predecessor()
        var predecessor2 = allIndices[i]
        predecessor2 = predecessor2.predecessor()
        var predecessor3 = allIndices[i]
        predecessor3 = predecessor3.predecessor()
        for p in [ predecessor1, predecessor2, predecessor3 ] {
          expectEqual(allIndices[i - 1], p, ${trace})
          expectEqual(
            expectedArray[i - 1], collection[p], ${trace}, sameValue: sameValue)
        }
      }
      for i in 1..<allIndices.count {
        var index = allIndices[i]
        index = index.predecessor()
        index = index.successor()
        expectEqual(allIndices[i], index, ${trace})
        expectEqual(
          expectedArray[i], collection[index], ${trace}, sameValue: sameValue)
      }
%   end
    }

    if true {
      var allIndices2: [C.Index] = []
      for i in collection.indices {
        allIndices2.append(i)
      }

      expectEqualSequence(
        allIndices, allIndices2, "iteration should not invalidate indices",
        stackTrace: ${stackTrace})

      expectEqualSequence(
        expectedArray, allIndices.map { collection[$0] },
        stackTrace: ${stackTrace}, sameValue: sameValue)
      expectEqualSequence(
        expectedArray, allIndices2.map { collection[$0] },
        stackTrace: ${stackTrace}, sameValue: sameValue)
    }
  }

  // FIXME: more checks for bidirectional and random access collections.
}

public func check${traversal}Collection<
  ${genericParam}, C : Collection
  where
  C.Iterator.Element == ${Element},
  C.Index : ${traversal}Index,
  ${Element} : Equatable
%  if traversal == 'RandomAccess':
  , C.Index.Stride == C.Index.Distance
% end
>(
  _ expected: ${Expected}, _ collection: C,
  ${TRACE},
  resiliencyChecks: CollectionMisuseResiliencyChecks = .all
) {
  check${traversal}Collection(
    expected, collection, ${trace},
    resiliencyChecks: resiliencyChecks) { $0 == $1 }
}
% end

// FIXME: merge into checkCollection()
public func checkSliceableWithBidirectionalIndex<
  ${genericParam}, S : Collection
  where
  S.Iterator.Element == ${Element},
  S.SubSequence.Iterator.Element == ${Element},
  S.Index : BidirectionalIndex,
  S.SubSequence : Collection,
  S.SubSequence.Index : BidirectionalIndex,
  ${Element} : Equatable
>(
  _ expected: ${Expected}, _ sliceable: S, ${TRACE}
) {
  // A `Sliceable` is a `Collection`.
  checkBidirectionalCollection(expected, sliceable, ${trace})

  let expectedArray = Array(expected)
  
  var start = sliceable.startIndex
  for startNumericIndex in 0...expectedArray.count {
    if start != sliceable.endIndex {
      start = start.successor()
      start = start.predecessor()
      start = start.successor()
      start = start.predecessor()
    }
    var end = start
    for endNumericIndex in startNumericIndex...expectedArray.count {
      if end != sliceable.endIndex {
        end = end.successor()
        end = end.predecessor()
        end = end.successor()
        end = end.predecessor()
      }
      let expectedSlice = expectedArray[startNumericIndex..<endNumericIndex]
      let slice = sliceable[start..<end]
      checkBidirectionalCollection(expectedSlice, slice, ${trace})

      if end != sliceable.endIndex {
        end = end.successor()
      }
    }
    if start != sliceable.endIndex {
      start = start.successor()
    }
  }
}

% end

public func nthIndex<C: Collection>(_ x: C, _ n: Int) -> C.Index {
  return x.startIndex.advanced(by: numericCast(n))
}

public func nth<C: Collection>(_ x: C, _ n: Int) -> C.Iterator.Element {
  return x[nthIndex(x, n)]
}

public func checkRangeReplaceable<
  C: RangeReplaceableCollection,
  N: Collection
  where
  C.Iterator.Element : Equatable,
  C.Iterator.Element == N.Iterator.Element
>(
  _ makeCollection: () -> C,
  _ makeNewValues: (Int) -> N
) {
  typealias A = C

  // First make an independent copy of the array that we can use for
  // comparison later.
  let source = Array<A.Iterator.Element>(makeCollection())

  for (ix, i) in source.indices.enumerated() {
    for (jx_, j) in (i..<source.endIndex).enumerated() {
      let jx = jx_ + ix
      
      let oldCount = jx - ix
      for newCount in 0..<(2 * oldCount) {
        let newValues = makeNewValues(newCount)

        func reportFailure(_ a: inout A, _ message: String) {
          print("\(message) when replacing indices \(ix)...\(jx)")
          print("  in \(Array(source)) with \(Array(newValues))")
          print("  yielding \(Array(a))")
          print("====================================")
          expectTrue(false)
        }

        var a = makeCollection()
     
        a.replaceSubrange(nthIndex(a, ix)..<nthIndex(a, jx), with: newValues)
        let growth = newCount - oldCount
        
        let expectedCount = source.count + growth
        let actualCount = numericCast(a.count) as Int
        if actualCount != expectedCount {
          reportFailure(
            &a, "\(actualCount) != expected count \(expectedCount)")
        }
        
        for (kx, k) in a.indices.enumerated() {
          let expectedValue = kx < ix ? nth(source, kx)
          : kx < jx + growth ? nth(newValues, kx - ix)
          : nth(source, kx - growth)

          if a[k] != expectedValue {
            reportFailure(
              &a,
              // FIXME: why do we need to break this string into two parts?
              "a[\(kx)] = "
              + "\(a[k]) != expected value \(expectedValue)")
          }
        }
      }
    }
  }
}

public func expectEqualSequence<
  Expected: Sequence,
  Actual: Sequence
  where
  Expected.Iterator.Element == Actual.Iterator.Element,
  Expected.Iterator.Element : Equatable
>(_ expected: Expected, _ actual: Actual, ${TRACE}) {
  expectEqualSequence(expected, actual, ${trace}) { $0 == $1 }
}

public func expectEqualSequence<
  Expected : Sequence,
  Actual : Sequence,
  T : Equatable,
  U : Equatable
  where
  Expected.Iterator.Element == Actual.Iterator.Element,
  Expected.Iterator.Element == (T, U)
>(_ expected: Expected, _ actual: Actual, ${TRACE}) {
  expectEqualSequence(
    expected, actual, ${trace}) {
    (lhs: (T, U), rhs: (T, U)) -> Bool in
    lhs.0 == rhs.0 && lhs.1 == rhs.1
  }
}

public func expectEqualSequence<
  Expected: Sequence,
  Actual: Sequence
  where
  Expected.Iterator.Element == Actual.Iterator.Element
>(_ expected: Expected, _ actual: Actual, ${TRACE},
  sameValue: (Expected.Iterator.Element, Expected.Iterator.Element) -> Bool) {

  if !expected.elementsEqual(actual, isEquivalent: sameValue) {
    expectationFailure("expected elements: \"\(expected)\"\n"
      + "actual: \"\(actual)\" (of type \(String(reflecting: actual.dynamicType)))",
      trace: ${trace})
  }
}

public func expectEqualsUnordered<
  Expected : Sequence,
  Actual : Sequence
  where
  Expected.Iterator.Element == Actual.Iterator.Element
>(
  _ expected: Expected, _ actual: Actual, ${TRACE},
  compare: (Expected.Iterator.Element, Expected.Iterator.Element)
    -> ExpectedComparisonResult
) {
  let x: [Expected.Iterator.Element] =
    expected.sorted(isOrderedBefore: compose(compare, { $0.isLT() }))
  let y: [Actual.Iterator.Element] =
    actual.sorted(isOrderedBefore: compose(compare, { $0.isLT() }))
  expectEqualSequence(
    x, y, ${trace}, sameValue: compose(compare, { $0.isEQ() }))
}

public func expectEqualsUnordered<
  Expected : Sequence,
  Actual : Sequence
  where
  Expected.Iterator.Element == Actual.Iterator.Element,
  Expected.Iterator.Element : Comparable
>(
  _ expected: Expected, _ actual: Actual, ${TRACE}
) {
  expectEqualsUnordered(expected, actual, ${trace}) {
    $0 < $1 ? .lt : $0 == $1 ? .eq : .gt
  }
}

public func expectEqualsUnordered<T : Comparable>(
  _ expected: [T], _ actual: [T], ${TRACE}
) {
  let x = expected.sorted()
  let y = actual.sorted()
  expectEqualSequence(x, y, ${trace})
}

/// A nominal type that is equivalent to a tuple of two elements.
///
/// We need a nominal type because we can't add protocol conformances to
/// tuples.
struct Pair<T : Comparable> : Comparable {
  init(_ first: T, _ second: T) {
    self.first = first
    self.second = second
  }

  var first: T
  var second: T
}

func == <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
  return lhs.first == rhs.first && lhs.second == rhs.second
}

func < <T>(lhs: Pair<T>, rhs: Pair<T>) -> Bool {
  return [ lhs.first, lhs.second ].lexicographicallyPrecedes(
    [ rhs.first, rhs.second ])
}

public func expectEqualsUnordered<
    Expected : Sequence,
    Actual : Sequence,
    T : Comparable
    where
    Actual.Iterator.Element == (key: T, value: T),
    Expected.Iterator.Element == (T, T)
>(
    _ expected: Expected, _ actual: Actual, ${TRACE}
) {
  func comparePairLess(_ lhs: (T, T), rhs: (T, T)) -> Bool {
    return [ lhs.0, lhs.1 ].lexicographicallyPrecedes([ rhs.0, rhs.1 ])
  }

  let x: [(T, T)] =
    expected.sorted(isOrderedBefore: comparePairLess)
  let y: [(T, T)] =
    actual.map { ($0.0, $0.1) }
      .sorted(isOrderedBefore: comparePairLess)

  func comparePairEquals(_ lhs: (T, T), rhs: (key: T, value: T)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
  }

  expectEqualSequence(x, y, ${trace}, sameValue: comparePairEquals)
}

public func expectEqualFunctionsForDomain<ArgumentType, Result : Equatable>(
    _ arguments: [ArgumentType], _ function1: ArgumentType -> Result,
    _ function2: ArgumentType -> Result
) {
  for a in arguments {
    let expected = function1(a)
    let actual = function2(a)
    expectEqual(expected, actual, "where the argument is: \(a)")
  }
}

public func expectEqualMethodsForDomain<
  SelfType, ArgumentType, Result : Equatable
>(
  _ selfs: [SelfType], _ arguments: [ArgumentType],
  _ function1: SelfType -> ArgumentType -> Result,
  _ function2: SelfType -> ArgumentType -> Result
) {
  for s in selfs {
    for a in arguments {
      let expected = function1(s)(a)
      let actual = function2(s)(a)
      expectEqual(
        expected, actual,
        "where the first argument is: \(s)\nand the second argument is: \(a)"
      )
    }
  }
}

public func expectEqualUnicodeScalars(
  _ expected: [UInt32], _ actual: String, ${TRACE}) {
  let actualUnicodeScalars = Array(
    actual.unicodeScalars.lazy.map { $0.value })
  
  if !expected.elementsEqual(actualUnicodeScalars) {
    expectationFailure(
      "expected elements: \"\(asHex(expected))\"\n"
      + "actual: \"\(asHex(actualUnicodeScalars))\"",
      trace: ${trace})
  }
}

public func expectPrinted<T>(
  expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
  let actual = String(object)
  if !patterns.contains(actual) {
    expectationFailure(
      "expected: any of \(String(reflecting: patterns))\n"
      + "actual: \(String(reflecting: actual))",
      trace: ${trace})
  }
}

public func expectPrinted<T>(
  _ expected: String, _ object: T, ${TRACE}
) {
  expectPrinted(expectedOneOf: [expected], object, ${trace})
}

public func expectDebugPrinted<T>(
  expectedOneOf patterns: [String], _ object: T, ${TRACE}
) {
  expectPrinted(expectedOneOf: patterns, String(reflecting: object), ${trace})
}

public func expectDebugPrinted<T>(
  _ expected: String, _ object: T, ${TRACE}
) {
  expectDebugPrinted(expectedOneOf: [expected], object, ${trace})
}

func compose<A, B, C>(_ f: A -> B, _ g: B -> C) -> A -> C {
  return { a in
    return g(f(a))
  }
}

/// A type that does not conform to any protocols.
///
/// This type can be used to check that generic functions don't rely on any
/// conformances.
public struct OpaqueValue<Underlying> {
  public var value: Underlying
  public var identity: Int

  public init(_ value: Underlying) {
    self.value = value
    self.identity = 0
  }

  public init(_ value: Underlying, identity: Int) {
    self.value = value
    self.identity = identity
  }
}

/// A type that conforms only to `Equatable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalEquatableValue : Equatable {
  public static var timesEqualEqualWasCalled: Int = 0

  public var value: Int
  public var identity: Int

  public init(_ value: Int) {
    self.value = value
    self.identity = 0
  }

  public init(_ value: Int, identity: Int) {
    self.value = value
    self.identity = identity
  }
}
public func == (
  lhs: MinimalEquatableValue,
  rhs: MinimalEquatableValue
) -> Bool {
  MinimalEquatableValue.timesEqualEqualWasCalled += 1
  return lhs.value == rhs.value
}

/// A type that conforms only to `Equatable` and `Comparable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalComparableValue : Equatable, Comparable {
  public static var timesEqualEqualWasCalled = ResettableValue(0)
  public static var timesLessWasCalled = ResettableValue(0)

  public static var equalImpl =
    ResettableValue<(Int, Int) -> Bool>({ $0 == $1 })
  public static var lessImpl =
    ResettableValue<(Int, Int) -> Bool>({ $0 < $1 })

  public var value: Int
  public var identity: Int

  public init(_ value: Int) {
    self.value = value
    self.identity = 0
  }

  public init(_ value: Int, identity: Int) {
    self.value = value
    self.identity = identity
  }
}

public func == (
  lhs: MinimalComparableValue,
  rhs: MinimalComparableValue
) -> Bool {
  MinimalComparableValue.timesEqualEqualWasCalled.value += 1
  return MinimalComparableValue.equalImpl.value(lhs.value, rhs.value)
}

public func < (
  lhs: MinimalComparableValue,
  rhs: MinimalComparableValue
) -> Bool {
  MinimalComparableValue.timesLessWasCalled.value += 1
  return MinimalComparableValue.lessImpl.value(lhs.value, rhs.value)
}

/// A type that conforms only to `Comparable` and `ForwardIndexType`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct MinimalComparableIndexValue : Comparable, ForwardIndex {
  public static var timesEqualEqualWasCalled = ResettableValue(0)
  public static var timesLessWasCalled = ResettableValue(0)

  public func successor() -> MinimalComparableIndexValue {
    return MinimalComparableIndexValue(value.successor())
  }

  public var value: Int
  public var identity: Int

  public init(_ value: Int) {
    self.value = value
    self.identity = 0
  }

  public init(_ value: Int, identity: Int) {
    self.value = value
    self.identity = identity
  }
}

public func == (
  lhs: MinimalComparableIndexValue,
  rhs: MinimalComparableIndexValue
) -> Bool {
  MinimalComparableIndexValue.timesEqualEqualWasCalled.value += 1
  return lhs.value == rhs.value
}

public func < (
  lhs: MinimalComparableIndexValue,
  rhs: MinimalComparableIndexValue
) -> Bool {
  MinimalComparableIndexValue.timesLessWasCalled.value += 1
  return lhs.value < rhs.value
}

% for kind in ['Value', 'Class']:
%   Self = 'MinimalHashable%s' % kind

/// A type that conforms only to `Equatable` and `Hashable`.
///
/// This type can be used to check that generic functions don't rely on any
/// other conformances.
public struct ${Self} : Equatable, Hashable {
  public static var timesEqualEqualWasCalled: Int = 0
  public static var timesHashValueWasCalled: Int = 0

  public var value: Int
  public var identity: Int

  public init(_ value: Int) {
    self.value = value
    self.identity = 0
  }

  public init(_ value: Int, identity: Int) {
    self.value = value
    self.identity = identity
  }

  public var hashValue: Int {
    ${Self}.timesHashValueWasCalled += 1
    return value.hashValue
  }
}

public func == (
  lhs: ${Self},
  rhs: ${Self}
) -> Bool {
  ${Self}.timesEqualEqualWasCalled += 1
  return lhs.value == rhs.value
}

% end

// ${'Local Variables'}:
// eval: (read-only-mode 1)
// End:
